package com.tiger.filter;

import com.alibaba.fastjson.JSON;
import com.tiger.utils.RedisUtils;
import com.tiger.service.transactional.InterfaceTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * @author HuXuehao (StudiousTiger)
 * @desc 这个类的作用是进行路由权限过滤
 * @date 2022/6/24
 */
@Component
@WebFilter(urlPatterns = "/*", filterName = "studioustigerFilter")
@Slf4j
public class AuthorityFilter implements Filter {
    @Value("${url.login.user}")
    private String LOGIN_URL;
    @Value("${url.login.admin}")
    private String LOGIN_URL_ADMIN;
    @Value("${url.no-login-user}")
    private String NO_LOGIN_USER_PATH;
    @Value("${url.no-login-admin}")
    private String NO_LOGIN_ADMIN_PATH;
    @Value("${url.disable}")
    private String DISABLE;

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private InterfaceTransactional transactional;

    // 无需做权限验证的访问路径的第一个子路径
    private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(
            new HashSet<>(Arrays.asList("/loginReg","/adminLog","/chat"))
    );

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        try {
            String userId = (String)httpServletRequest.getSession().getAttribute("userId");
            String adminId = (String)httpServletRequest.getSession().getAttribute("adminId");
            String requestURI = httpServletRequest.getRequestURI();
            // 获取路径中的第一个子路径（将会用来判断是否是登录注册的接口）
            String pathFirstIndex = "/"+requestURI.split("/")[1];

            // 获取requestURI对应的接口的权限以及接口的状态
            String[] arr = getInterfaceStatus(requestURI);
            // 接口禁用
            if ("1".equals(arr[1])) {
                // 验证不通过，请求转发到 DISABLE
                httpServletRequest.getRequestDispatcher(DISABLE).forward(httpServletRequest, httpServletResponse);
            }
            // 无需权限控制，对应登录注册页面的请求
            else if (ALLOWED_PATHS.contains(pathFirstIndex)) {
                chain.doFilter(request, response);
            }
            // 没有对应的接口
            else if (arr == null) {
                // 验证不通过，请求转发到 DISABLE
                httpServletRequest.getRequestDispatcher(DISABLE).forward(httpServletRequest, httpServletResponse);
            }
            // 如果是用户接口且用户session为空，验证不通过；如果是管理员接口且管理员session为空，验证不通过
            else if ((userId == null && "user".equalsIgnoreCase(arr[0]))) {
                // 验证不通过，请求转发到 NOT_LOGIN_PATH
                httpServletRequest.getRequestDispatcher(NO_LOGIN_USER_PATH).forward(httpServletRequest, httpServletResponse);
            }
            else if ((adminId == null && "admin".equalsIgnoreCase(arr[0]))) {
                // 验证不通过，请求转发到 NOT_LOGIN_PATH
                httpServletRequest.getRequestDispatcher(NO_LOGIN_ADMIN_PATH).forward(httpServletRequest, httpServletResponse);
            }
            // 验证通过
            else {
                chain.doFilter(request, response);
            }
        } catch (Exception e) {
            // 验证不通过，请求转发到 DISABLE
            httpServletRequest.getRequestDispatcher(DISABLE).forward(httpServletRequest, httpServletResponse);
        }
    }

    /**
     * 该方法的作用是查看接口角色以及状态 index 0 存放角色，index 1中存放状态
     * @param url 请求接口
     * @return
     */
    private String[] getInterfaceStatus(String url) throws Exception {
        // 从缓存中获取记录
        Object[] interfaceInfos = redisUtils.hGetAllKey("interfaceInfo");
        String urlPrefix = null;
        for (Object info : interfaceInfos) {
            if (url.contains(info.toString())) {
                urlPrefix = info.toString();
            }
        }
        // 缓存穿透
        if (urlPrefix == null) {
            // 同步数据库&&同步缓存
            transactional.synchronizationInterface();
            return null;
        } else {
            // 获取缓存中的记录
            String interfaceInfoStr = (String) redisUtils.hget("interfaceInfo", urlPrefix);
            // 返回缓存中的数据
            return JSON.parseObject(interfaceInfoStr, String[].class);
        }
    }
}
